const nodes7 = require('nodes7');
const { EventEmitter } = require('events');

class S7Connector extends EventEmitter {
  constructor(options) {
    super();
    this.options = options;
    this.conn = new nodes7();
    this.isConnected = false;
    this.variables = {};
    this.readInterval = null;
    this.healthCheckInterval = null;
    this.reconnectInterval = null;
    this.reconnectAttempts = 0;
    this.maxReconnectAttempts = 5;
    this.reconnectDelay = 5000; // 5秒
    // 添加读写操作队列，避免并发冲突
    this.operationQueue = Promise.resolve();
    this.isOperationInProgress = false;
  }

  // 连接PLC
  async connect() {
    return new Promise((resolve, reject) => {
      console.log('🔄 正在连接PLC，连接参数:', this.options);
      
      this.conn.initiateConnection(this.options, (err) => {
        if (err) {
          this.isConnected = false;
          console.error('❌ PLC连接失败:', err);
          this.emit('error', err);
          
          // 启动自动重连机制
          if (this.reconnectAttempts < this.maxReconnectAttempts) {
            this.startAutoReconnect();
          }
          
          reject(new Error(`PLC连接失败: ${err.message}`));
          return;
        }
        
        this.isConnected = true;
        this.reconnectAttempts = 0;
        this.emit('connected');
        console.log('✅ S7 PLC连接成功');
        
        // 启动健康检查
        this.startHealthCheck();
        
        resolve();
      });
    });
  }
  
  // 启动自动重连
  startAutoReconnect() {
    if (this.reconnectInterval) {
      clearInterval(this.reconnectInterval);
    }
    
    this.reconnectInterval = setInterval(async () => {
      this.reconnectAttempts++;
      console.log(`🔄 尝试重新连接PLC (${this.reconnectAttempts}/${this.maxReconnectAttempts})...`);
      
      try {
        await this.connect();
        console.log('✅ PLC重连成功');
        clearInterval(this.reconnectInterval);
        this.reconnectInterval = null;
      } catch (err) {
        console.error(`❌ PLC重连失败 (${this.reconnectAttempts}/${this.maxReconnectAttempts}):`, err);
        
        if (this.reconnectAttempts >= this.maxReconnectAttempts) {
          console.error('❌ 达到最大重连次数，停止重连');
          clearInterval(this.reconnectInterval);
          this.reconnectInterval = null;
        }
      }
    }, this.reconnectDelay);
  }
  
  // 启动健康检查
  startHealthCheck() {
    if (this.healthCheckInterval) {
      clearInterval(this.healthCheckInterval);
    }
    
    // 每30秒执行一次健康检查
    this.healthCheckInterval = setInterval(() => {
      this.performHealthCheck();
    }, 30000);
  }
  
  // 执行健康检查
  async performHealthCheck() {
    try {
      console.log('🔍 执行PLC连接健康检查...');
      
      // 尝试读取一个简单的变量来验证连接是否正常
      const testVar = 'DB1,X0.0'; // 使用一个通常不会引起问题的位变量
      
      await this._readVariablesInternal([testVar]);
      console.log('✅ PLC连接健康检查通过');
    } catch (err) {
      console.error('❌ PLC连接健康检查失败，连接可能已断开:', err);
      
      // 如果健康检查失败，尝试重新连接
      if (this.isConnected) {
        this.isConnected = false;
        this.emit('disconnected');
        this.startAutoReconnect();
      }
    }
  }

  // 断开连接
  disconnect() {
    // 清除所有定时器
    if (this.readInterval) {
      clearInterval(this.readInterval);
      this.readInterval = null;
    }
    
    if (this.reconnectInterval) {
      clearInterval(this.reconnectInterval);
      this.reconnectInterval = null;
    }
    
    if (this.healthCheckInterval) {
      clearInterval(this.healthCheckInterval);
      this.healthCheckInterval = null;
    }
    
    this.conn.dropConnection();
    this.isConnected = false;
    this.emit('disconnected');
    console.log('🔌 S7 PLC连接已断开');
  }

  // 读取变量 - 添加队列控制
  async readVariables(vars) {
    // 将读取操作加入队列，确保串行执行
    return this.operationQueue = this.operationQueue.then(() => this._readVariablesInternal(vars))
      .catch(err => {
        console.error('❌ 读取变量队列执行失败:', err);
        throw err;
      });
  }

  // 内部读取变量实现
  _readVariablesInternal(vars) {
    return new Promise((resolve, reject) => {
      if (!this.isConnected) {
        const error = new Error('PLC未连接');
        console.error('❌ 读取变量失败:', error.message);
        
        // 尝试自动重连
        if (!this.reconnectInterval) {
          this.startAutoReconnect();
        }
        
        reject(error);
        return;
      }

      console.log('📥 正在读取变量:', vars);
      
      // 检查是否有操作正在进行
      if (this.isOperationInProgress) {
        console.warn('⚠️ 检测到并发操作，等待前一操作完成');
      }
      
      this.isOperationInProgress = true;
      
      // 清除之前添加的所有变量项
      this.conn.removeItems();
      
      // 添加当前请求的变量项
      this.conn.addItems(vars);
      
      this.conn.readAllItems((err, values) => {
        this.isOperationInProgress = false;
        
        if (err) {
          console.error('❌ 读取变量失败:', err);
          
          // 检测连接状态，如需要则更新
          if (this.isConnected) {
            this.isConnected = false;
            this.emit('disconnected');
            console.log('🔍 连接状态更新: { isConnected: false, hasConnector: true, connectorConnected: false }');
            
            // 启动自动重连
            this.startAutoReconnect();
          }
          
          reject(new Error(`读取变量失败: ${err.message}`));
          return;
        }
        
        console.log('✅ 变量读取成功:', values);
        console.log('🔍 连接状态正常: { isConnected: true, hasConnector: true, connectorConnected: true }');
        resolve(values);
      });
    });
  }

  // 写入变量 - 添加队列控制
  async writeVariable(name, value) {
    // 将写入操作加入队列，确保串行执行
    return this.operationQueue = this.operationQueue.then(() => this._writeVariableInternal(name, value))
      .catch(err => {
        console.error('❌ 写入变量队列执行失败:', err);
        throw err;
      });
  }

  // 内部写入变量实现
  _writeVariableInternal(name, value) {
    return new Promise((resolve, reject) => {
      if (!this.isConnected) {
        const error = new Error('PLC未连接');
        console.error('❌ 写入变量失败:', error.message);
        
        // 尝试自动重连
        if (!this.reconnectInterval) {
          this.startAutoReconnect();
        }
        
        reject(error);
        return;
      }

      console.log('📤 正在写入变量:', name, '值:', value, '类型:', typeof value);
      
      // 检查是否有操作正在进行
      if (this.isOperationInProgress) {
        console.warn('⚠️ 检测到并发操作，等待前一操作完成');
      }
      
      this.isOperationInProgress = true;
      
      // 确保写入的数据格式正确
      const items = {};
      items[name] = value;
      
      // 使用writeItems方法写入变量
      this.conn.writeItems([name], [value], (err) => {
        this.isOperationInProgress = false;
        
        if (err) {
          console.error('❌ 写入变量失败:', err);
          
          // 检测连接状态，如需要则更新
          if (this.isConnected) {
            this.isConnected = false;
            this.emit('disconnected');
            console.log('🔍 连接状态更新: { isConnected: false, hasConnector: true, connectorConnected: false }');
            
            // 启动自动重连
            this.startAutoReconnect();
          }
          
          // 提供更详细的错误信息
          const errorMessage = `写入变量 ${name} 失败: ${err.message}`;
          reject(new Error(errorMessage));
          return;
        }
        
        console.log('✅ 变量写入成功:', name, '值:', value);
        console.log('🔍 连接状态正常: { isConnected: true, hasConnector: true, connectorConnected: true }');
        // 返回写入结果，包含成功状态和写入的值
        resolve({ success: true, name, value });
      });
    });
  }

  // 设置周期性读取
  setReadInterval(vars, interval = 1000) {
    if (this.readInterval) {
      clearInterval(this.readInterval);
    }
    
    this.readInterval = setInterval(async () => {
      try {
        const values = await this.readVariables(vars);
        this.emit('data', values);
      } catch (err) {
        console.error('❌ 周期性读取失败:', err);
        this.emit('error', err);
      }
    }, interval);
  }
}

module.exports = S7Connector;